Namespace("org.wattdepot.gdata.makahiki");

// Creates an energy status summary pane for the Makahiki application.
org.wattdepot.gdata.makahiki.EnergyStatusSummary = function(configuration, source) {

  // Parameters for this visualization.
  var configuration = configuration;
  var source = source;
  var startColumn = configuration.getEnergySummaryStartColumn(source);
  var backgroundColor = configuration.widgetBackgroundColor;
  var width = configuration.energyStatusSummaryWidth;
  var green = configuration.greenIndicatorColor;
  var yellow = configuration.yellowIndicatorColor;
  var red = configuration.redIndicatorColor;

  // The top-level interface. 
  function draw(energySummaryDatatable, baselineDatatable, currentPowerDatatable, id) {
    var element = document.getElementById(id);
    addTopLevelStyle(element);
    addTitleDiv(element, id, energySummaryDatatable);
    addHeaderDiv(element, id + '_Overall_', 'Overall Status');
    addSmileyDiv(element, id, energySummaryDatatable, baselineDatatable);
    addHeaderDiv(element, id + '_CurrentPower_', 'Current Power');
    addCurrentPowerDiv(element, id, currentPowerDatatable, baselineDatatable);
    addHeaderDiv(element, id + '_RecentTrends_', 'Recent Trends');

    var hourlySparklineColumn = startColumn + configuration.energySummaryLastHrColumnOffset;
    addSparkDiv(element, id + '_hourly_', energySummaryDatatable, hourlySparklineColumn, 0, 5);
    var dailySparklineColumn = startColumn + configuration.energySummaryLastDayColumnOffset;
    addSparkDiv(element, id + '_daily_', energySummaryDatatable, dailySparklineColumn, 0, 23, yellow);
    var weeklySparklineColumn = startColumn + configuration.energySummaryLastWeekColumnOffset;
    addSparkDiv(element, id + '_weekly_', energySummaryDatatable, weeklySparklineColumn, 0, 6, green);
    var baselineHeader = addHeaderDiv(element, id + '_useVbaseline_', 'Use vs. Baseline');
    fixBaselineHeaderStyle(baselineHeader);
    addBaselineDiv(element, id, energySummaryDatatable);
    addLastUpdateDiv(element, id, energySummaryDatatable);
  }

  // Adds 'global' CSS styling to the top-level div passed into this instance.
  function addTopLevelStyle(element) {
    element.style.backgroundColor = backgroundColor;
    element.style.margin = '0 auto';
    //element.style.width = width;  // don't add this, messes up the sparkline table.
  }

  // Adds standard div CSS styling (which cannot be applied to the spark lines).
  function addDivStyle(element) {
    element.style.width = width + 'px';
    element.style.textAlign = 'center';
  }

  // Adds special header CSS styling.
  function addHeaderStyle(element) {
    element.style.margin = '6px auto 3px auto';
    element.style.width = width + 'px';
    element.style.textAlign = 'center';
    element.style.backgroundColor = configuration.widgetHeaderColor;
    element.style.color = configuration.widgetHeaderTextColor;
    //element.style.fontVariant = 'small-caps';
    element.style.fontWeight = 'normal';
    element.style.fontSize = '0.8em';
  }

  // The baseline chart has a 30px white space at top.  
  // We use this so that we can slide the baseline chart 'under' this header.
  function fixBaselineHeaderStyle (element) {
    element.style.position = 'relative';
    element.style.zIndex = '+1';
  }

  function addInfoStyle(element) {
    element.style.fontSize = '0.7em';
    element.style.fontWeight = 'normal';
    element.style.width = width + 'px';
    element.style.margin = "0 auto";
    element.style.textAlign = 'center';
    element.style.color = configuration.widgetHeaderColor;
  }

  function addTitleDiv(element, id, energySummaryDatatable) {
    var divId = id + '__Title';
    var div = getElementByIdOrCreate(divId, 'div');
    addDivStyle(div);
    // Special CSS just for the title.
    div.style.fontSize = '1.0em';
    div.style.fontWeight = 'bold';
    div.style.color = configuration.widgetHeaderColor;
    var sourceColumn = configuration.getEnergySummaryStartColumn(source);
    div.innerHTML = energySummaryDatatable.getFormattedValue(0, sourceColumn);
    element.appendChild(div);
  }

  function addHeaderDiv(element, id, headerString) {
    var divId = id + '__Header';
    var div = getElementByIdOrCreate(divId, 'div');
    addHeaderStyle(div);
    div.innerHTML = headerString;
    element.appendChild(div);
    return div;
  }

  function addSmileyDiv(element, id, energySummaryDatatable, baselineDatatable) {
    var divId = id + '__Smiley';
    var div = getElementByIdOrCreate(divId, 'div');
    addDivStyle(div);
    element.appendChild(div);
    var smileyImgId = divId + '_img';
    var img = getElementByIdOrCreate(smileyImgId, 'img');
    img.setAttribute('src', getSmileyUrl(energySummaryDatatable));  
    div.appendChild(img);
  }

  // Compare final cumulative energy for the week to the baseline cumulative energy for the week.
  // If final is plus or minus 5% of the baseline, return indifferent smiley.
  // If final is 5% or less than baseline, return green smiley.
  // Otherwise final is 5% or more so return red smiley.
  function getSmileyUrl(energySummaryDatatable) {
    var useColumn = startColumn + configuration.energySummaryCumulativeEnergyColumnOffset;
    var baselineColumn = startColumn + configuration.energySummaryCumulativeBaselineColumnOffset;
    var finalUse = energySummaryDatatable.getValue(6, useColumn);
    var finalBaseline = energySummaryDatatable.getValue(6, baselineColumn);
    if (finalUse > (finalBaseline + (finalBaseline * 0.05))) {
      return configuration.smileySadUrl;
    }
    else if (finalUse < (finalBaseline - (finalBaseline * 0.05))) {
      return configuration.smileyHappyUrl;
    }
    else {
      return configuration.smileyIndifferentUrl;
    }
  }

  function addCurrentPowerDiv(element, id, currentPowerDatatable, baselineDatatable) {
    var divId = id + '__CurrentPower';
    var div = getElementByIdOrCreate(divId, 'div');
    // Add default and current power specific styles.
    addDivStyle(div);
    div.style.fontSize = '1.5em';
    div.style.fontWeight = 'bold';
    // Set the current power from the datatable.
    var row = configuration.getCurrentPowerDataRow(source);
    var column = configuration.currentPowerDataPowerColumn;
    var currentPower = currentPowerDatatable.getFormattedValue(row, column);
    // Get baseline power
    var baselineRow = configuration.getBaselineDataRow(source);
    var baselineColumn = configuration.getBaselineDataColumn();
    var baselinePower = baselineDatatable.getFormattedValue(baselineRow, baselineColumn);

    // Set the color of the power based upon the baseline vs. power comparaison
    div.style.color = configuration.getBaselineDataColor(currentPower, baselinePower);
    div.innerHTML = currentPower + ' W';

    // Add current power div
    element.appendChild(div);

    // Now add the baseline div.
    var infoId = id + '__CurrentPowerInfo';
    var infoDiv = getElementByIdOrCreate(infoId, 'div');
    addInfoStyle(infoDiv);
    infoDiv.innerHTML = '(baseline: ' + baselinePower + ' kW)';
    element.appendChild(infoDiv);
  }

  function addSparkDiv(element, id, energySummaryDatatable, column, startRow, endRow) {
    var divId = id + '__Sparkline_' + column;
    var div = getElementByIdOrCreate(divId, 'div');
    element.appendChild(div);
    var view = new google.visualization.DataView(energySummaryDatatable);
    view.setColumns([column]);
    view.setRows(startRow, endRow);
    var chart = new google.visualization.ImageSparkLine(div);
    chart.draw(view, {color: getSparklineColor(view),
                      width: width, 
                      height: 30, 
                      //backgroundColor : backgroundColor, // doesn't look good.
                      showAxisLines: false,  
                      showValueLabels: false,
                      labelPosition: 'left'});
  }

  // Return the color to be associated with the sparkline given the data.
  // If the final val is plus or minus 5% of the first val, then color it yellow.
  // If the final val is at least 5% less, then color it green.
  // Otherwise the final val is at least 5% more and therefore color it red.
  function getSparklineColor(view) {
    var firstVal = view.getValue(0, 0);
    var lastVal = view.getValue((view.getNumberOfRows() - 1), 0);
    var color;
    if (lastVal > (firstVal + (firstVal * 0.05))) {
      color = configuration.redIndicatorColor;
    }
    else if (lastVal < (firstVal - (firstVal * 0.05))) {
      color = configuration.greenIndicatorColor;
    }
    else {
      color = configuration.yellowIndicatorColor;
    }
    return color;
  }


  function addBaselineDiv(element, id, energySummaryDatatable) {
    var divId = id + '__BaselineVsActual';
    var div = getElementByIdOrCreate(divId, 'div');
    element.appendChild(div);
    div.style.margin = '-20px auto 0'; // Move baseline chart up 20 pixels.
    div.style.textAlign = 'center';

    var view = new google.visualization.DataView(energySummaryDatatable);
    view.setColumns([startColumn + configuration.energySummaryDateColumnOffset,
		     startColumn + configuration.energySummaryCumulativeBaselineColumnOffset,
		     startColumn + configuration.energySummaryCumulativeEnergyColumnOffset
		    ]);
    view.setRows(0,6);
    var chart = new google.visualization.AreaChart(div);
    chart.draw(view, {
      width: width, 
      height: width, 
      backgroundColor : backgroundColor,
      colors: ['green', 'black'],
      legend: 'none',
      pointSize: 0
    });
  }

  function addLastUpdateDiv(element, id, datatable) {
    var divId = id + '__LastUpdate';
    var div = getElementByIdOrCreate(divId, 'div');
    addInfoStyle(div);
    var lastUpdateColumn = startColumn + configuration.energySummaryLastUpdateColumnOffset;
    div.innerHTML = datatable.getFormattedValue(0,lastUpdateColumn);
    element.appendChild(div);
  }

  // Returns the pre-existing element with id 'id', or else creates and returns a new element with type elementType and that id.
  function getElementByIdOrCreate(id, elementType) {
    var element = document.getElementById(id);
    if (element) {
      return element;
    }
    else {
      element = document.createElement(elementType);
      element.setAttribute("id", id);
      return element;

    }
  }

  return {
    // Public interface to this function. 
    draw : draw
  };
}


